﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics;

namespace SimpleIR
{
	/// <summary>
	/// This class containes all the information that we use to model composite type structures (structures-including the primitive type structures, classes, and interfaces).
	/// </summary>
	public sealed class IRTypeDescription
	{
		/// <summary>
		/// Name of the type that this description is for (this is mainly for debugging ease).
		/// </summary>
		private readonly string m_nameoftype;

		/// <summary>
		/// Type qualifiers.
		/// </summary>
		private readonly TypeQualifiers m_typequalifier;

		/// <summary>
		/// True if this type is part of a recursive type definition.
		/// </summary>
		private bool m_isrectype;

		/// <summary>
		/// Set of all Types this this inherits from (or extends), NOT including this
		/// </summary>
		private readonly HashSet<IRType> m_inheritsfrom;

		/// <summary>
		/// Set of all subtypes, includes "this"
		/// </summary>
		private readonly HashSet<IRType> m_allsubtypes;

		/// <summary>
		/// Set of all fields accessable from "this"
		/// </summary>
		private readonly HashSet<IRMemberField> m_allvisfields;

		/// <summary>
		/// Set of all the access paths accessable in "this"
		/// </summary>
		private readonly List<IRBasicAccessPath> m_allterminalaccesspaths;

		/// <summary>
		/// List of all fields defined in "this" type.
		/// </summary>
		private readonly List<IRMemberField> m_alldefinthisfields;

		/// <summary>
		/// The member methods implemented by this type.
		/// </summary>
		private readonly List<IRVirtualInvoke> m_implementsmethods;

		/// <summary>
		/// The member methods that this has explicit overrides for. 
		/// Maps from the type of the explicit override and the method to the method implementation in this 
		/// that should be used.
		/// </summary>
		private readonly Dictionary<Tuple<IRType, IRInvokeSig>, IRVirtualInvoke> m_explicitoverridemap;

		/// <summary>
		/// The other memory types that this is recursive with.
		/// </summary>
		private readonly HashSet<IRType> m_recwithtypes;

		/// <summary>
		/// Create the memory type object.
		/// </summary>
		/// <param name="tt">The type that this description is going to be associated with.</param>
		public IRTypeDescription(IRType tt, TypeQualifiers tqual)
		{
			this.m_nameoftype = tt.TypeName;
			this.m_typequalifier = tqual;

			this.m_isrectype = false;

			this.m_inheritsfrom = new HashSet<IRType>();
			
			this.m_allsubtypes = new HashSet<IRType>();
			this.m_allsubtypes.Add(tt);

			this.m_allvisfields = new HashSet<IRMemberField>();
			this.m_allterminalaccesspaths = new List<IRBasicAccessPath>();
			this.m_alldefinthisfields = new List<IRMemberField>();
			
			this.m_implementsmethods = new List<IRVirtualInvoke>();
			this.m_explicitoverridemap = new Dictionary<Tuple<IRType, IRInvokeSig>, IRVirtualInvoke>();
			this.m_recwithtypes = new HashSet<IRType>();
		}

		public override String ToString()
		{ return "Decl For: " + this.m_nameoftype; }

		/// <summary>
		/// Add a new field to the definition information and return the interned field for this.
		/// </summary>
		public IRMemberField LoadFieldInfoAsNeeded(IRType defClass, String name, IRType fieldType, FieldQualifiers qual)
		{
			IRMemberField retmf = this.m_allvisfields.FirstOrDefault((IRMemberField mf) => mf.FieldName.Equals(name));

			if(retmf == null)
			{
				retmf = new IRMemberField(defClass, name, fieldType, qual);
				this.m_allvisfields.Add(retmf);
				this.m_alldefinthisfields.Add(retmf);
			}

			return retmf;
		}

		/// <summary>
		/// Add a new field to the definition information and return the interned field for this.
		/// </summary>
		public IRMemberField LookupFieldInClass(String name)
		{
			IRMemberField sf = this.m_allvisfields.FirstOrDefault((IRMemberField mf) => mf.FieldName.Equals(name));
			
			if(sf != null)
				return sf;
			else
				throw new ArgumentException("Hmm missing thing?");
		}

		/// <summary>
		/// Add the set of methods that are declared in this to the definition information.
		/// </summary>
		public void LoadMemberImplInfo(List<IRVirtualInvoke> methods, Dictionary<Tuple<IRType, IRInvokeSig>, IRVirtualInvoke> overridemap)
		{
			this.m_implementsmethods.AddRange(methods);

			foreach(Tuple<IRType, IRInvokeSig> vv in overridemap.Keys)
				this.m_explicitoverridemap.Add(vv, overridemap[vv]);
		}

		/// <summary>
		/// Add the set of types that this is recursive with.
		/// </summary>
		public void FinalizeRecInfo()
		{
			if(this.m_recwithtypes.Count != 0)
				this.m_isrectype = true;
		}

		/// <summary>
		/// True if the type is a recursive type.
		/// </summary>
		public bool IsRecursiveType 
		{ get { return this.m_isrectype; } }

		/// <summary>
		/// Return the type qualifier tag.
		/// </summary>
		public TypeQualifiers TypeQualifierInfo
		{ get { return this.m_typequalifier; } } 

		/// <summary>
		/// True if the type is a builtin type.
		/// </summary>
		public bool IsBuiltinType 
		{ get { return (this.m_typequalifier & TypeQualifiers.BuiltinTag) != 0; } }

		/// <summary>
		/// True if the type is an abstract type.
		/// </summary>
		public bool IsAbstractType 
		{ get { return (this.m_typequalifier & TypeQualifiers.AbstractTag) != 0; } }

		/// <summary>
		/// Return a set of all types (NOT including this type) that this inherits from or extends.
		/// DO NOT MODIFY (unless you really really know what you are doing)
		/// </summary>
		public HashSet<IRType> AllInheritsExtends
		{ get { return this.m_inheritsfrom; } }

		/// <summary>
		/// Return a set of all types (includeing this type) that this is recursive with.
		/// DO NOT MODIFY (unless you really really know what you are doing)
		/// </summary>
		public HashSet<IRType> AllRecursiveWith
		{ get { return this.m_recwithtypes; } }

		/// <summary>
		/// Return a set of all subtypes (includeing this type) of this.
		/// DO NOT MODIFY (unless you really really know what you are doing)
		/// </summary>
		public HashSet<IRType> AllSubTypes
		{ get { return this.m_allsubtypes; } }

		/// <summary>
		/// Return a set of all visible fields.
		/// DO NOT MODIFY (unless you really really know what you are doing)
		/// </summary>
		public HashSet<IRMemberField> AllVisibleFields
		{ get { return this.m_allvisfields; } }

		/// <summary>
		/// Return a set of all access paths that are terminal -- they end at a primitive or pointer field or they read through <c>struct</c> definitions flattening them.
		/// DO NOT MODIFY (unless you really really know what you are doing)
		/// </summary>
		public List<IRBasicAccessPath> AllTerminalAccessPaths
		{ get { return this.m_allterminalaccesspaths; } }

		/// <summary>
		/// Return the field with the given name which MUST be defined in this type.
		/// </summary>
		public IRMemberField GetFieldWithNameDefIn(string name)
		{ return this.m_alldefinthisfields.Find((IRMemberField f) => name.Equals(f.FieldName)); }

		/// <summary>
		/// Return a set of all the fields defined in this type.
		/// DO NOT MODIFY (unless you really really know what you are doing)
		/// </summary>
		public List<IRMemberField> AllDefInFields
		{ get { return this.m_alldefinthisfields; } }

		/// <summary>
		/// Return a list of all the member methods that this directly implements (i.e. that are 
		/// implemented in this class directly and not inherited from super type implementations).
		/// DO NOT MODIFY (unless you really really know what you are doing)
		/// </summary>
		public List<IRVirtualInvoke> AllImplMemberMethods
		{ get { return this.m_implementsmethods; } }

		/// <summary>
		/// Return a list of all the member methods that this directly implements (i.e. that are 
		/// implemented in this class directly and not inherited from super type implementations).
		/// DO NOT MODIFY (unless you really really know what you are doing)
		/// </summary>
		public Dictionary<Tuple<IRType, IRInvokeSig>, IRVirtualInvoke> AllExplicitOverridesMap
		{ get { return this.m_explicitoverridemap; } }
	}
}
